#pragma once

#include "Logger.h"

#define Context_ptr std::tr1::shared_ptr<HttpContext>

//These are the ascii control characters between 0x00 (NULL) and 0x40 (Space).
#define INVALID_HTTP_CTL \\0x0\\0x1\\0x2\\0x3\\0x4\\0x5\\0x6\\0x7\\0x8\\0x9\\0xA\\0xB\\0xC\\0xD\\0xE\\0xF\\0x10\\0x11\\0x12\\0x13\\0x14\\0x15\\0x16\\0x17\\0x18\\0x19\\0x1A\\0x1B\\0x1C\\0x1D\\0x1E\\0x1F\\0x20\\0x7F
//0x42 is a double-quote character. Couldn't put \\" in the macro.
#define INVALID_HTTP_TOKEN_CHARS ()<>@,;:\\\\\/\\[\\]?=\\{\\}\\0x42

#define REGEX_RESPONSE_HEADER_NAME_CLEANER "[INVALID_HTTP_TOKEN_CHARS INVALID_HTTP_CTL]+"

using namespace std;

class HttpContext {
private:
	LPEXTENSION_CONTROL_BLOCK ECB;
	size_t InputDataOffset;

	friend class HttpResponse;
	friend class HttpRequest;
	HttpRequest* Request;
	HttpResponse* Response;

public:
	HttpContext(LPEXTENSION_CONTROL_BLOCK lpECB);
	~HttpContext();

	string GetServerVariable(const string& variableName);
	vector<BYTE> GetRequestBytes(const size_t bytesNeeded);
	static HttpContext* get_Current();

	HttpRequest* get_Request() const {
		return Request;
	}

	HttpResponse* get_Response() const {
		return Response;
	}
};

class HttpRequest {
private:
	friend class HttpContext;
	HttpContext* Context;
	queue< BYTE, list<BYTE> > LocalRequestBuffer;

	

	HttpRequest() throw() { }
public:
	~HttpRequest() throw() { }
	void EnsureBuffer();
	string Read(const DWORD length);
	string ReadLine();
};

class HttpResponse {
private:
	friend class HttpContext;
	HttpContext* Context;
	PyObject* PythonEnvironment;
	shared_ptr<NameValueCollection> Headers;
	BOOL HeadersSent;
	string Status;

	HttpResponse();

	void SetItem(const string& variableName);
	void SetItem(const string& variableName, const string& alias);
	void BuildWsgiEnvironment();
	void StoreHeaders(PyObject* responseHeaders);
	PyObject* CompileScriptToModule(const string& scriptPath, const string& virtualPath);
	

public:
	~HttpResponse() throw() {
		GILock lock;
		Py_DECREF(PythonEnvironment);
	}


	/* Property getter/setters */
	string get_ContentType() const;
	void set_ContentType(const string& contentType);
	
	void set_ContentLength(ULONGLONG contentLength);
	ULONGLONG get_ContentLength() const;

	string get_Status() const;
	void set_Status(const string& status);

	tr1::shared_ptr<NameValueCollection> get_Headers() const;

	/* Methods */
	void ExecuteWsgiScript(const string& filePath, const string& virtualPath);
	void SendHeaders();
	PyObject* start_response(PyObject* args);
	PyObject* write(PyObject* args);
	void Write(const string& content);
	void End();
};